Skip to content

Add SeederApi PlayData delete scheduled job#7281

Draft
MGibson1 wants to merge 5 commits intomainfrom
arch/add-hosted-service-to-clear-old-play-data
Draft

Add SeederApi PlayData delete scheduled job#7281
MGibson1 wants to merge 5 commits intomainfrom
arch/add-hosted-service-to-clear-old-play-data

Conversation

@MGibson1
Copy link
Copy Markdown
Member

@MGibson1 MGibson1 commented Mar 23, 2026

Use Quartz-based hosted service to clear old play data

We need to stop possible bloat of databases should users of a seeded data fail to appropriately clean up after themselves.

Using the hosted services present in other projects, this adds an alive job and play data delete job to the SeederApi

We need to stop possible bloat of databases should users of a seeded data fail to appropriately clean up after themselves.

Using the hosted services present in other projects, this adds an alive job and play data delete job to the SeederApi
Development servers are unlikely to be running at midnight UTC, so we need to delete more frequently to ensure data is cleaned up. The Job still deletes things older than a day, it just checks much more frequently, now.
@MGibson1 MGibson1 added the ai-review-vnext Request a Claude code review using the vNext workflow label Mar 23, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 23, 2026

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

This PR adds a Quartz-based scheduled job (DeleteOldPlayDataJob) to the SeederApi that cleans up play data older than 1 day every 15 minutes. The implementation follows established patterns from other projects (e.g., Api/Jobs). The GetAllPlayIdsQuery is extended with a DateTime olderThan overload, and the DeleteAllAsync controller endpoint is updated to support age-based filtering. Integration tests properly remove the hosted service to avoid parallel execution issues, matching the pattern in ApiApplicationFactory.

Code Review Details

No findings. The code is clean, follows existing codebase conventions, and correctly implements the Quartz job infrastructure pattern used elsewhere in the repository.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 58.14%. Comparing base (783fd5a) to head (0c10e4a).
⚠️ Report is 58 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7281      +/-   ##
==========================================
+ Coverage   57.74%   58.14%   +0.40%     
==========================================
  Files        2043     2054      +11     
  Lines       89868    90771     +903     
  Branches     7991     8059      +68     
==========================================
+ Hits        51895    52780     +885     
- Misses      36115    36120       +5     
- Partials     1858     1871      +13     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@MGibson1 MGibson1 requested a review from theMickster March 23, 2026 22:52
@theMickster
Copy link
Copy Markdown
Contributor

Couple thoughts
Have we found if there are scenarios where we would not want the Seeded data deleted using this scheduled job?
For clarity, we are focused here on cleaning up after manual testing, automated testing, or both?

@MGibson1
Copy link
Copy Markdown
Member Author

All data tagged with a PlayId (i.e. PlayData) is by definition opted in to be ephemeral by the client requesting it's creation through the x-play-id header.

If, for some reason, you want to seed data that is not ephemeral, all you have to do is not include that header data and this job will not touch it.

In some respects, we're assuming good actors here, but the endpoints on publicly accessible lower environments are not publicly accessible.

public class AliveJob : BaseJob
{
private readonly GlobalSettings _globalSettings;
private HttpClient _httpClient = new HttpClient();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Noting this as a known anti-pattern that causes socket exhaustion. Did we copy this from the src/Admin job?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure did. I don't know what issue, do we have a fix? Is this bump job unnecessary?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AliveJob is fine — the issue is private HttpClient _httpClient = new HttpClient(). Directly instantiating HttpClient as a field is a known antipattern that causes socket exhaustion under load because each instance gets its own connection pool and doesn't respect DNS TTLs.

The fix is to inject IHttpClientFactory and call httpClientFactory.CreateClient() in the constructor. We'll also need services.AddHttpClient() in program startup. The job itself can stay as-is.

@MGibson1 MGibson1 requested a review from theMickster March 31, 2026 19:49
@sonarqubecloud
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown
Contributor

Logo
Checkmarx One – Scan Summary & Detailsf2a84fd8-a869-4e61-80e1-911adadb5543


New Issues (122) Checkmarx found the following issues in this Pull Request
# Severity Issue Source File / Package Checkmarx Insight
1 CRITICAL Stored_XSS /src/SharedWeb/Health/HealthCheckServiceExtensions.cs: 61
detailsThe method embeds untrusted data in generated output with WriteAsync, at line 60 of /src/SharedWeb/Health/HealthCheckServiceExtensions.cs. This ...
Attack Vector
2 CRITICAL Stored_XSS /util/Server/Startup.cs: 57
detailsThe method embeds untrusted data in generated output with WriteAsync, at line 59 of /util/Server/Startup.cs. This untrusted data is embedded int...
Attack Vector
3 MEDIUM CSRF /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 145
detailsMethod at line 145 of /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs gets a parameter from a user request from request. T...
Attack Vector
4 MEDIUM CSRF /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 145
detailsMethod at line 145 of /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs gets a parameter from a user request from request. T...
Attack Vector
5 MEDIUM CSRF /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 97
detailsMethod at line 97 of /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs gets a parameter from a user request from model. This...
Attack Vector
6 MEDIUM CSRF /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 97
detailsMethod at line 97 of /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs gets a parameter from a user request from model. This...
Attack Vector
7 MEDIUM CSRF /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 229
detailsMethod at line 229 of /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs gets a parameter from a user request from model. Thi...
Attack Vector
8 MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1592
detailsMethod at line 1592 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
Attack Vector
9 MEDIUM CSRF /src/Api/Tools/Controllers/SendsController.cs: 73
detailsMethod at line 73 of /src/Api/Tools/Controllers/SendsController.cs gets a parameter from a user request from id. This parameter value flows thro...
Attack Vector
10 MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 307
detailsMethod at line 307 of /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs gets a parameter from a user request from organizationUser...
Attack Vector
11 MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 307
detailsMethod at line 307 of /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs gets a parameter from a user request from model. This par...
Attack Vector
12 MEDIUM CSRF /src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 128
detailsMethod at line 128 of /src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs gets a parameter from a user request from user. This p...
Attack Vector
13 MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 217
detailsMethod at line 217 of /src/Api/Auth/Controllers/AccountsController.cs gets a parameter from a user request from model. This parameter value flow...
Attack Vector
14 MEDIUM CSRF /src/Api/Public/Controllers/CollectionsController.cs: 91
detailsMethod at line 91 of /src/Api/Public/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value ...
Attack Vector
15 MEDIUM CSRF /src/Api/Public/Controllers/CollectionsController.cs: 91
detailsMethod at line 91 of /src/Api/Public/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value ...
Attack Vector
16 MEDIUM CSRF /src/Api/Public/Controllers/CollectionsController.cs: 91
detailsMethod at line 91 of /src/Api/Public/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value ...
Attack Vector
17 MEDIUM CSRF /src/Api/Public/Controllers/CollectionsController.cs: 91
detailsMethod at line 91 of /src/Api/Public/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value ...
Attack Vector
18 MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 176
detailsMethod at line 176 of /src/Api/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value flows ...
Attack Vector
19 MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 176
detailsMethod at line 176 of /src/Api/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value flows ...
Attack Vector
20 MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 176
detailsMethod at line 176 of /src/Api/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value flows ...
Attack Vector
21 MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 176
detailsMethod at line 176 of /src/Api/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value flows ...
Attack Vector
22 MEDIUM CSRF /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 173
detailsMethod at line 173 of /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs gets a parameter from a user request from model. Thi...
Attack Vector
23 MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 452
detailsMethod at line 452 of /src/Api/Auth/Controllers/AccountsController.cs gets a parameter from a user request from model. This parameter value flow...
Attack Vector
24 MEDIUM CSRF /src/Api/Dirt/Controllers/OrganizationReportsController.cs: 189
detailsMethod at line 189 of /src/Api/Dirt/Controllers/OrganizationReportsController.cs gets a parameter from a user request from request. This paramet...
Attack Vector
25 MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 531
detailsMethod at line 531 of /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs gets a parameter from a user request from model. This par...
Attack Vector
26 MEDIUM CSRF /src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 87
detailsMethod at line 87 of /src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs gets a parameter from a user request from user. This pa...
Attack Vector
27 MEDIUM CSRF /src/Api/Billing/Controllers/VNext/OrganizationBillingVNextController.cs: 107
detailsMethod at line 107 of /src/Api/Billing/Controllers/VNext/OrganizationBillingVNextController.cs gets a parameter from a user request from organiza...
Attack Vector
28 MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1451
detailsMethod at line 1451 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
Attack Vector
29 MEDIUM CSRF /src/Api/Dirt/Controllers/OrganizationReportsController.cs: 233
detailsMethod at line 233 of /src/Api/Dirt/Controllers/OrganizationReportsController.cs gets a parameter from a user request from request. This paramet...
Attack Vector
30 MEDIUM CSRF /src/Api/Dirt/Controllers/OrganizationReportsController.cs: 286
detailsMethod at line 286 of /src/Api/Dirt/Controllers/OrganizationReportsController.cs gets a parameter from a user request from request. This paramet...
Attack Vector
31 MEDIUM CSRF /src/Api/Dirt/Controllers/OrganizationReportsController.cs: 189
detailsMethod at line 189 of /src/Api/Dirt/Controllers/OrganizationReportsController.cs gets a parameter from a user request from request. This paramet...
Attack Vector
32 MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1451
detailsMethod at line 1451 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
Attack Vector
33 MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1451
detailsMethod at line 1451 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
Attack Vector
34 MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 289
detailsMethod at line 289 of /src/Api/AdminConsole/Controllers/GroupsController.cs gets a parameter from a user request from orgUserId. This parameter ...
Attack Vector
35 MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1419
detailsMethod at line 1419 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
Attack Vector
36 MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1480
detailsMethod at line 1480 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
Attack Vector
37 MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1184
detailsMethod at line 1184 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
Attack Vector
38 MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1068
detailsMethod at line 1068 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
Attack Vector

More results are available on the CxOne platform


Fixed Issues (3) Great job! The following issues were fixed in this Pull Request
Severity Issue Source File / Package
MEDIUM CSRF /src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 55
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 534
MEDIUM SSL_Verification_Bypass /src/Core/Platform/Mail/Delivery/MailKitSmtpMailDeliveryService.cs: 81


services.AddControllers();

Jobs.JobsHostedService.AddJobsServices(services);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Deleting data with a hosted service always give me a little heartburn. Have we implemented opt-in techniques using environment settings in other places, by chance? I have done that in the past where my teams implemented background services that mutated data and gave us a better feel of control (especially when developing) knowing that one had to explicitly set the setting to ON to mutate/delete data?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. Are you concerned with unintentional data loss? To some extent the goal of this job is to enforce that play data is ephemeral.

That can be a server setting if we want, I suppose, but maybe a better tweak would be a lifetime?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the ephemeral environments, I am not too concerned because I would not expect an ephemeral environment to live long enough to see the job run. Since the intention is really deleting this ephemeral data from long lived environments then I'm cool with it.

Only real issue is if you're developing tests locally or on one of the QA team VMs and you're expecting data to be there over a couple days (like a weekend) then you'd better be ready for the Seeder to clean itself up.

Did we add a README.md? (Sorry on the GH app so hard to go back n forth).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review-vnext Request a Claude code review using the vNext workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants